package com.mall.annotation;

import com.mall.db.service.OperationLogService;
import com.mall.db.uitls.IpUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;

@Aspect
@Component
public class OperationLogAspect {
    @Resource(name = "operationLogService")
    private OperationLogService ols;

    //切入点，利用自定义注解作为切入的位置，及自定义注解的地方的那个方法就是切入点
    @Pointcut("@annotation(com.mall.annotation.OperationLog)")
    public void  pointcut(){}

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point){
        Object result=null;
        //记录执行开始时间
        long beginTime=System.currentTimeMillis();
        try {
            //执行方法
            result=point.proceed();
        }catch (Throwable e){
            e.printStackTrace();
        }
        //执行完成后的时间
        long end=System.currentTimeMillis();
        System.out.println("执行需要的时间"+(end-beginTime));



        saveOperationLog(point,result);

        return result;
    }
   private  void saveOperationLog(ProceedingJoinPoint point,Object result){
        //获取注解描述，即注解的传值
       MethodSignature signature=(MethodSignature) point.getSignature();
       Method method=signature.getMethod();//获取执行的方法
       OperationLog ol=method.getAnnotation(OperationLog.class);//获取注解内容
       com.mall.db.domain.OperationLog log=new com.mall.db.domain.OperationLog();
       if(ol!=null){
           log.setAction(ol.value());
           log.setType(ol.type());
       }
       //获取request
       HttpServletRequest request=getRequest();
       log.setUser("admin");//TODO 登录用户信息
       log.setIp(IpUtils.getIpAddress(request));
       //获取执行的方法
       String className=point.getTarget().getClass().getName();
       String methodName= signature.getName();
       log.setMethod(className+"."+methodName+"()");
       //获取执行方法中的参数及参数值
       Object[] args=point.getArgs();
       LocalVariableTableParameterNameDiscoverer l=new LocalVariableTableParameterNameDiscoverer();
       String []paramNames=l.getParameterNames(method);
       if(args!=null && paramNames!=null){
           String param="";
           int i=0;
           for (Object arg:args) {
               param+=(i==0?"":",")+paramNames[i]+":"+args[i];
               i++;
           }
           log.setParams(param);
       }
       //把执行结果转换为map
       Map<String,Object> res=(Map<String, Object>) result;
       if(!StringUtils.isEmpty(res.get("is"))){
//           boolean b=(boolean) res.get("is");
           log.setResult(res.get("is")+"");
       }
       if(!StringUtils.isEmpty(res.get("msg"))){
//           boolean b=(boolean) res.get("is");
           log.setComment(res.get("msg")+"");
       }
       //执行日志保存
       ols.save(log);
   }

    /**
     * 获取request方法
     * @return
     */
   public HttpServletRequest getRequest(){
        return ((ServletRequestAttributes)
                Objects.requireNonNull(RequestContextHolder.getRequestAttributes()))
                        .getRequest();
   }
}
